package odgs;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import odgs.listener.ExplorerListener;
import odgs.listener.ExplorerNodeModifyListener;

public class Explorer implements ExplorerNodeModifyListener, Serializable
{
	private Directory root;
	private List<ExplorerListener> explorerModifyListeners;
	private Directory position;
	
	public Explorer()
	{
		explorerModifyListeners = new ArrayList<ExplorerListener>();
	}
	
	public Explorer(Directory root)
	{
		this();
		this.root = root;
		position = root;
		root.addExplorerNodeModifyListener(this);
	}

	public void add(ExplorerNode node)
	{
		String rollbackPosition = getPosition();

		if(node.getPath().equals(""))
		{
			if(position.getPath().equals(""))
				node.setPath(position.getPath() + position.getName());
			else
				node.setPath(position.getPath() + position.getName() + "/");
		}
		else
		{
			setPosition(node.getPath());
		}
		position.add(node);	
		node.addExplorerNodeModifyListener(this);
		notifyAddedEvent(position ,node);
		
		setPosition(rollbackPosition);
	}

	private void notifyAddedEvent(ExplorerNode parent, ExplorerNode node)
	{
		for(ExplorerListener listener : explorerModifyListeners)
		{
			listener.added(parent, node);
		}
	}
	
	public void addExplorerModifyListener(ExplorerListener listener)
	{
		explorerModifyListeners.add(listener);
	}
	
	public int getTotalDirectorySize()
	{
		return root.getTotalDirectorySize();
	}

	public void modified(ExplorerNode node)
	{
		notifyUpdateNodeEvent(node);
	}

	private void notifyUpdateNodeEvent(ExplorerNode node) {
		for(ExplorerListener l : explorerModifyListeners)
		{
			l.modified(node);
		}
	}

	public void remove(ExplorerNode node)
	{
		Directory dir = root.getDirectory(node.getPath());
		if(dir != null)
		{
			dir.remove(node);
			notifyRemovedEvent(dir, node);
		}
	}

	private void notifyRemovedEvent(ExplorerNode parent, ExplorerNode node)
	{
		for(ExplorerListener l : explorerModifyListeners)
		{
			l.removed(parent,node);
		}
	}

	public void move(ExplorerNode target, String destPath)
	{
		Directory cutDir = root.getDirectory(target.getPath());
		ExplorerNode source = cutDir.getNode(target.getName());
		cutDir.remove(source);
		source.setPath(destPath);
		Directory pasteDir = root.getDirectory(destPath);
		pasteDir.add(source);
		notifyMoveEvent(target);
	}

	private void notifyMoveEvent(ExplorerNode target)
	{
		for (ExplorerListener l : explorerModifyListeners)
		{
			l.moved(target);
		}
	}

	public void copy(ExplorerNode target, String destPath)
	{
		Directory path = root.getDirectory(target.getPath());
		ExplorerNode dest = path.getNode(target.getName()).clones();
		dest.setPath(destPath);
		Directory dir = root.getDirectory(destPath);
		dir.add(dest);
		notifyCopyEvent(dest);
	}

	private void notifyCopyEvent(ExplorerNode dest)
	{
		for (ExplorerListener l : explorerModifyListeners)
		{
			l.copied(dest);
		}
	}

	public int getTotalContentsSize()
	{
		return root.getTotalContentsSize();
	}

	public void setPosition(String position)
	{
		if(canSetPosition(position))
		{
			position = getPath(position);
			this.position = root.getDirectory(position);
			notifySetPositionEvent();
		}
	}

	private void notifySetPositionEvent()
	{
		for(ExplorerListener listener : explorerModifyListeners)
		{
			if(root != position)
				listener.setedPosition(position.getPath() + position.getName() + "/");
			else
				listener.setedPosition(position.getPath() + position.getName());
		}
	}

	public List<Directory> getDirectorys()
	{	
		if(position == null)
			return new ArrayList<Directory>();
		return position.getDirectorys();
	}

	public String getPosition()
	{
		if("".equals(position.getPath()))
			return position.getPath()+ position.getName();
		else
			return position.getPath()+ position.getName() + "/";
	}

	public List<Contents> getContents()
	{
		if(position == null)
			return new ArrayList<Contents>();
		return position.getContents();
	}

	public ExplorerNode getAt(String name)
	{
		return position.getAt(name);
	}

	public int getDirectorySize()
	{
		return position.getDirectorySize();
	}

	public int getContentsSize()
	{
		return position.getContentsSize();
	}

	public int getNodeSize()
	{
		return position.getNodeSize();
	}

	public Directory getRoot()
	{
		return root;
	}
	
	private String getPath(String position)
	{
		char temp = position.charAt(0);
		if(temp != '/')
		{
			if(this.position == root)
				position = this.position.getPath() + this.position.getName() + position;
			else
				position = this.position.getPath() + this.position.getName() + "/"+ position;
		}
		return position;
	}

	public boolean canSetPosition(String position)
	{
		position = getPath(position);
		if(root.getDirectory(position) != null)
			return true;
		else 
			return false;
	}

	public void goParent()
	{
		if(root != this.position)
		{
			setPosition(this.position.getPath());
		}
	}

	public boolean canRename(String name)
	{
		return isNode(name);
	}

	public boolean isNode(String name)
	{
		return position.isNode(name);
	}

	public ExplorerNode getNode(String name)
	{
		return position.getNode(name);
	}

	public Directory getDirectory(String name)
	{
		ExplorerNode node = position.getNode(name);
		if(node.canChildren())
			return (Directory) node;
		else
			return null;
	}

	public void rename(ExplorerNode node, String dest)
	{
		Directory dir = position.getDirectory(node.getPath());
		ExplorerNode nodes = dir.getNode(node.getName());
		if(nodes != null)
			nodes.setName(dest);
	}

	public boolean isRoot()
	{
		if(root == position)
			return true;
		else 
			return false;
	}

	public Contents getContent(String name)
	{
		ExplorerNode node = position.getNode(name);
		if(!node.canChildren())
			return (Contents) node;
		else
			return null;
	}

	public List<ExplorerNode> findByName(String name) {
		return root.findByName(name);
	}

	public List<ExplorerNode> findByType(String type) {
		return root.findByType(type);
	}

	public void changeName(String sourceName, String targetName) {
		ExplorerNode node = position.getNode(sourceName);
		node.setName(targetName);
	}
}